/*
 * Copyright 2008. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the Apache License, Version 2.0. You
 * can find a copy of the license at:
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */

package com.sinai.mshab.widgets;

import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.Widget;

/**
 * Exercise the {@link AbstractRadioButtonGroup} class. We're looking to test
 * all of it's methods since they are used by several subclasses.
 * 
 * @author Arthur Kalmenson
 */
public class AbstractRadioButtonGroupTst extends GWTTestCase {

	/**
	 * The {@link AbstractRadioButtonGroup} to test. We use a mock that extends
	 * the abstract class and uses a {@link HorizontalPanel}.
	 */
	private AbstractRadioButtonGroup mockRadioCollection;

	/**
	 * Used to check if a listener was notified.
	 */
	private boolean notified;

	/**
	 * Test to insure that creating an {@link AbstractRadioButtonGroup} with
	 * null and invalid arguments throws an {@link IllegalArgumentException}.
	 */
	public void testInvalidConstArgs() {
		invalidConstArgs(null, null);
		invalidConstArgs("hello", null);
		invalidConstArgs(null, new String[] { "hello" });
		invalidConstArgs("", new String[] { "hi", "hello" });
	}

	/**
	 * Takes in null arguments and insures that an
	 * {@link IllegalArgumentException} is thrown.
	 * 
	 * @param name
	 *            the name of the collection.
	 * @param choices
	 *            the choices for the collection.
	 */
	private void invalidConstArgs(String name, String[] choices) {
		try {
			mockRadioCollection = new MockAbstractRadioCollection(name, choices);
			fail("Should have thrown an IllegalArgumentException");
		} catch (IllegalArgumentException e) {
			assertTrue(true);
		}
	}

	/**
	 * Test create a {@link MockAbstractRadioCollection} with empty choices. We
	 * expect no {@link RadioButton}s to be created and the collection to be
	 * empty.
	 */
	public void testEmptyChoices() {
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] {});
		assertEquals(0, mockRadioCollection.size());
	}

	/**
	 * Test creating a single {@link RadioButton} in a collection.
	 */
	public void testCreateSingleRadio() {
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] { "blah" });

		// insure that the radio button was created and that all the styles were
		// set appropriately.
		assertEquals("mshab-RadioButtonGroup", mockRadioCollection
				.getStylePrimaryName());
		assertEquals(1, mockRadioCollection.size());
		assertEquals("blah", mockRadioCollection.getRadio("blah").getText());
	}

	/**
	 * Test creating multiple {@link RadioButton}s in a collection.
	 */
	public void testCreateMultipleRadio() {
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] { "hi", "hello", "test" });

		// check that the appropriate RadioButtons were created
		assertEquals(3, mockRadioCollection.size());
		assertEquals("hi", mockRadioCollection.getRadio("hi").getText());
		assertEquals("hello", mockRadioCollection.getRadio("hello").getText());
		assertEquals("test", mockRadioCollection.getRadio("test").getText());
	}

	/**
	 * Try creating multiple a collection with choices that have duplicates. We
	 * need to insure that duplicates aren't added.
	 */
	public void testCreateMultipleRadioDuplicateText() {
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] { "hi", "hello", "hi", "test", "test" });

		// insure that we only get three (duplicates don't get added).
		assertEquals(3, mockRadioCollection.size());
	}

	/**
	 * Test isChecked, getValue and setValue on an empty
	 * {@link AbstractRadioButtonGroup}, we expect null in all cases.
	 */
	public void testIsCheckedAndValueEmptyCollection() {
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] {});
		assertEquals(false, mockRadioCollection.isChecked());
		assertEquals(null, mockRadioCollection.getValue());

		// try to set a value, insure we get null.
		mockRadioCollection.setValue("blah");
		assertEquals(null, mockRadioCollection.getValue());
	}

	/**
	 * Test to insure that isChecked, getValue and setValue work with a single
	 * {@link RadioButton}.
	 */
	public void testIsCheckedAndValueSingle() {

		// create a new one and insure nothing is checked or set.
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] { "blah" });
		assertFalse(mockRadioCollection.isChecked());
		assertEquals(null, mockRadioCollection.getValue());

		// set the value to something not there, insure still null.
		mockRadioCollection.setValue("test");
		assertEquals(null, mockRadioCollection.getValue());

		// now set to existing text and insure it is checked and value is
		// returned.
		mockRadioCollection.setText("blah");
		assertTrue(mockRadioCollection.isChecked());
		assertEquals("blah", mockRadioCollection.getText());

		// insure that getValue() is the same as getText().
		assertEquals("blah", mockRadioCollection.getValue());
	}

	/**
	 * Test isChecked, setValue and getValue with a collection that has many
	 * {@link RadioButton}s. We set to existing values, then change the value
	 * and set to a non-existing value.
	 */
	public void testIsCheckedAndValueMultiple() {

		// create a new one and insure nothing is checked or set.
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] { "hi", "hello", "test", "testing" });
		assertFalse(mockRadioCollection.isChecked());
		assertEquals(null, mockRadioCollection.getValue());

		// now set to existing value and insure it is checked and value is
		// returned.
		mockRadioCollection.setValue("hello");
		assertTrue(mockRadioCollection.isChecked());
		assertEquals("hello", mockRadioCollection.getValue());

		// try setting to a different value.
		mockRadioCollection.setValue("testing");
		assertTrue(mockRadioCollection.isChecked());
		assertEquals("testing", mockRadioCollection.getValue());

		// set to a nonexisting value, and make sure it's still set to the
		// previous value.
		mockRadioCollection.setValue("not there");
		assertTrue(mockRadioCollection.isChecked());
		assertEquals("testing", mockRadioCollection.getValue());

		// insure that getText() is the same as getValue().
		assertEquals("testing", mockRadioCollection.getText());
	}

	/**
	 * Test to insure that when we change the value that a
	 * {@link ChangeListener} is not fired. This will keep with GWT's current
	 * model where listeners are not notified when values change
	 * programmatically.
	 */
	public void testChangeListenerFiringNullChange() {
		mockRadioCollection = new MockAbstractRadioCollection("test",
				new String[] { "hi", "hello", "test", "testing" });
		mockRadioCollection.addChangeListener(new ChangeListener() {
			public void onChange(Widget arg0) {
				// if this was called, we should fail.
				fail("Change listener should not have been called.");
			}
		});
		mockRadioCollection.setValue("blah");
		mockRadioCollection.setValue("test");
	}

	/**
	 * The mock {@link AbstractRadioButtonGroup} that uses a
	 * {@link HorizontalPanel} as it's panel.
	 * 
	 * @author Arthur Kalmenson
	 */
	private class MockAbstractRadioCollection extends AbstractRadioButtonGroup {

		public MockAbstractRadioCollection(String name, String[] choices) {
			super(name, choices, new HorizontalPanel());
		}
	}

	@Override
	public String getModuleName() {
		return "com.sinai.mshab.MshabWidgets";
	}
}
